#include "auxfunctions.h"
bool IsLeapYear(int YYYY)
{
	if(YYYY%100!=0)
	{
		if(YYYY%4==0)
			return true;
		else
			return false;
	}
	else if(YYYY%400!=0)
	{
		return false;
	}
	else
	{
		return true;
	}
}
int YYYYMMDD2Int(int YYYY, int MM, int DD)
{
	int daysInt=0;
	int monthDays[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	if(YYYY<100)
		YYYY=2000+YYYY; //e.g. change 07 to 2007
	if(YYYY<2000||MM>12||MM<1||DD<1)
	{
		cout<<"Wrong Date!"<<endl;
		exit(0);
	}
	//how to judge the DD>? //not finished yet


	for(int yearCount=2000; yearCount<YYYY; yearCount++)
	{
		if( IsLeapYear(yearCount))
		{
			daysInt+=366;
		}
		else
		{
			daysInt+=365;
		}
	}
	for(int monthCount=1; monthCount<MM;monthCount++)
	{
		daysInt+=monthDays[monthCount];
	}
	if (IsLeapYear(YYYY)&&MM>2)
		daysInt++;
	daysInt+=DD;
	daysInt--;
	return daysInt;
}
int YYYYMMDDhhmmss2Int(int YYYY, int MM, int DD, int hh, int mm, int ss)
{
	int timeInt;
	if(hh>23||hh<0||mm>59||mm<0||ss>59||ss<0)
	{
		cout<<"Wrong hhmmss!"<<endl;
		exit(0);
	}
	timeInt=YYYYMMDD2Int(YYYY,MM,DD)*86400+hh*3600+mm*60+ss;

	return timeInt;
}
int YYYYMMDD2Int(string str)
{
	int YYYY, MM, DD;
	string temp;
	if(str.length()==6)
	{
		temp.assign(str, 0,2);
		YYYY = atoi(temp.c_str());
		temp.assign(str, 2, 2);
		MM=atoi(temp.c_str());
		temp.assign(str,4,2);
		DD=atoi(temp.c_str());
	}
	else if(str.length()==8)
	{
		temp.assign(str, 0,4);
		YYYY = atoi(temp.c_str());
		temp.assign(str, 4, 2);
		MM=atoi(temp.c_str());
		temp.assign(str,6,2);
		DD=atoi(temp.c_str());
	}
	else
	{
		cout<<"Wrong date! "<<endl;
		YYYY=-2000;
		MM=0;
		DD=0;
	}
	return YYYYMMDD2Int(YYYY,MM,DD);
}
int YYYYMMDDhhmmss2Int(string str)
{
	int YYYY, MM, DD, hh, mm,ss;
	string temp;
	if(str.length()==12)
	{
		temp.assign(str, 0,2);
		YYYY = atoi(temp.c_str());
		temp.assign(str, 2, 2);
		MM=atoi(temp.c_str());
		temp.assign(str,4,2);
		DD=atoi(temp.c_str());
		temp.assign(str,6,2);
		hh=atoi(temp.c_str());
		temp.assign(str,8,2);
		mm=atoi(temp.c_str());
		temp.assign(str,10,2);
		ss=atoi(temp.c_str());
	}
	else if(str.length()==14)
	{
		temp.assign(str, 0,4);
		YYYY = atoi(temp.c_str());
		temp.assign(str, 4, 2);
		MM=atoi(temp.c_str());
		temp.assign(str,6,2);
		DD=atoi(temp.c_str());
		temp.assign(str,8,2);
		hh=atoi(temp.c_str());
		temp.assign(str,10,2);
		mm=atoi(temp.c_str());
		temp.assign(str,12,2);
		ss=atoi(temp.c_str());
	}
	else
	{
		cout<<"Wrong date! "<<endl;
		YYYY=-2000;
		MM=0;
		DD=0;
		hh=0;
		mm=0;
		ss=0;
	}
	return YYYYMMDDhhmmss2Int(YYYY,MM,DD,hh,mm,ss);
}
string Int2YYYYMMDD(int daynum)
{
	int monthDays[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	int handlingMonth=1;
	int handlingYear=2000;
	int handlingDay=1;
	while((daynum-365-(int)IsLeapYear(handlingYear))>=0)
	{
		daynum=daynum-365-(int)IsLeapYear(handlingYear);
		handlingYear++;
	}
	while((daynum-monthDays[handlingMonth]-(int)(handlingMonth==2 && IsLeapYear(handlingYear)))>=0)
	{
		daynum=daynum-monthDays[handlingMonth]-(int)(handlingMonth==2 && IsLeapYear(handlingYear));
		handlingMonth++;
	}
	handlingDay=daynum+1;
	stringstream ss;
	ss<<setfill('0')<<setw(4)<<handlingYear<<setfill('0')<<setw(2)<<handlingMonth<<setfill('0')<<setw(2)<<handlingDay;
	string result;
	ss>>result;
	return result;
}
string Int2YYYYMMDDhhmmss(int secnum)
{
	int daynum=(int)secnum/86400;
	int secinaday=(int)secnum%86400;
	int hh_int=(int)secinaday/3600;
	int mm_int=(int)((secinaday%3600)/60) ;
	int ss_int=(int)((secinaday%3600)%60) ;
	stringstream ss;
	ss<<setfill('0')<<setw(2)<<hh_int<<setfill('0')<<setw(2)<<mm_int<<setfill('0')<<setw(2)<<ss_int;
	string hhmmss;
	ss>>hhmmss;

	string YYYYMMDD=Int2YYYYMMDD(daynum);
	string YYYYMMDDhhmmss=YYYYMMDD+hhmmss;
	return YYYYMMDDhhmmss;
}
bool IsTheFileInTheTaskTimePeriod(string fileFullName, int taskStartTimeInt, int taskEndTimeInt)
{
	string temp;
	temp.assign(fileFullName, fileFullName.size()-13, 8); //!!!Oh my god this works in the new file name system!!
	temp=temp+"0000";
	int filePossibleStart=YYYYMMDDhhmmss2Int(temp);
	int filePossibleEnd=filePossibleStart+86400;
	if ( ( filePossibleStart<=taskEndTimeInt ) && ( filePossibleEnd >= taskStartTimeInt) )
		return true;
	else
		return false;
}

double interp(double x1, double y1, double x2, double y2, double x)
{
	if(fabs(x1-x2)<0.00000001)
	{
		cout<<"Error interpolating with x1=x2"<<endl;
		return 0;
	}
	else
	{
		double y=(y2-y1)/(x2-x1)*(x-x1)+y1;
		return y;
	}
}


void OnHelp(void)
{

	cout<<"\nUsage: newlidarpro -iatdfcmvUOLSYG  [height]  YYYYMMDDhhmmss YYYYMMDDhhmmss [average minutes] [limit]\n\n";

	cout<<"   The parameters \"[height] YYYYMMDDhhmmss YYYYMMDDhhmmss [aver_min] [limit]\" should be arrayed as the above order.\n\n";

	cout<<"   -i: Output normalized relative backscattering signal image data.\n";
	cout<<"   -a: Output aerosol extinction coefficient image data.\n";
	cout<<"   -t: Output time series aerosol extinction coefficient data at a given 'height'.\n";
	cout<<"   -d: Output aerosol optical depth below a given 'limit'.\n";
	cout<<"   -f: Output float data instead of color index to be used in image.\n";
	cout<<"   -c: For test: Output cloud bottom.\n";
	cout<<"   -m: Not finished yet! Output mixing layer height.\n";
	cout<<"   -v: New! Handling data with a certain minutes average.\n";
	cout<<"   -U: New! Make Afterpulse data. (But it seems unneccecary for this new lidar? )\n";
	cout<<"   -O: New! Make Overlap Coefficients .\n";
	cout<<"   -L: New! Calculate Lidar Constant with AOD.\n";
	cout<<"   -S: New! Calculate LIDAR back scattering ratio (s_a) with AOD, maybe seems like lidarpro's -r option.\n";
	cout<<"   -Y: New! Output the detailed data for diagn**** (How to spell this word?).\n";
	cout<<"   -G: New! Output original data instead of color index like 0~255 (-ia), or 0~1 (-iaf) .\n\n";

	cout<<"   'height' in meters or kms(if less than 60, it's automatically turned into km) should be the second parameter if option 't' used.\n";
	cout<<"   'YYYYMMDDhhmmss' and 'YYYYMMDDhhmmss' are the 'From' time and 'To' time for the averaged aerosol extinction coefficient profile.\n";
	cout<<"       -- Do not forget the minutes and seconds...\n";
	cout<<"   [average minutes] should be following the two YYYYMMDDhhmmss's if option 'v' used.\n";
	cout<<"   'limit' in meters or kms (if less than 60, it's automatically turned into km)) should be the last parameter if the option 'd' used.\n\n";
	
	cout<<"   -p: Output averaged aerosol extinction coefficient profile data from a given time 'YYYYMMDDHHMMSS' to another.\n";
	cout<<"   -r: A test on calculating the AOD from different LIDAR back scattering ratio within a given time period data:YYYYMMDDHHMMSS YYYYMMDDHHMMSS.\n\n"; 

	cout<<  "   ! You may need to set up the file \"setting.ini\" before running this program for the first time.\n";
   
	cout<<  "   Programmer: YANG Dongwei, student of LI Chengcai, November 2007\n\n";
	cout<<  "   Latest modification finished on November, O Damn it, it's already December 2...\n\n";
}


LidarProArg AnalysisArg(int ac, char *av[])
{

	LidarProArg tempArg;
	//This is not strict enough... so .. I don't know what will happen if you enter a wrong parametre...
	if( ac<=3 ) 
	{
		OnHelp();
		exit (FAILED);
	}

	tempArg.averMinInt=0;
	tempArg.lidarpro_height=0;
	tempArg.lidarpro_limit=0;
	//Setting all switches
	if(strstr(av[1],"i")!=NULL)
        tempArg.b_i=true;
	else
		tempArg.b_i=false;

	if(strstr(av[1],"a")!=NULL)
        tempArg.b_a=true;
	else
		tempArg.b_a=false;

	if(strstr(av[1],"t")!=NULL)
        tempArg.b_t=true;
	else
		tempArg.b_t=false;

	if(strstr(av[1],"p")!=NULL)
        tempArg.b_p=true;
	else
		tempArg.b_p=false;

	if(strstr(av[1],"d")!=NULL)
        tempArg.b_d=true;
	else
		tempArg.b_d=false;

	if(strstr(av[1],"f")!=NULL)
        tempArg.b_f=true;
	else
		tempArg.b_f=false;

	if(strstr(av[1],"r")!=NULL)
        tempArg.b_r=true;
	else
		tempArg.b_r=false;

	if(strstr(av[1],"c")!=NULL)
        tempArg.b_c=true;
	else
		tempArg.b_c=false;

	if(strstr(av[1],"m")!=NULL)
        tempArg.b_m=true;
	else
		tempArg.b_m=false;

	if(strstr(av[1],"v")!=NULL)
		tempArg.b_v=true;
	else
		tempArg.b_v=false;

	if(strstr(av[1],"S")!=NULL)
        tempArg.b_S=true;
	else
		tempArg.b_S=false;

	if(strstr(av[1],"L")!=NULL)
        tempArg.b_L=true;
	else
		tempArg.b_L=false;

	if(strstr(av[1],"O")!=NULL)
        tempArg.b_O=true;
	else
		tempArg.b_O=false;

	if(strstr(av[1],"U")!=NULL)
        tempArg.b_U=true;
	else
		tempArg.b_U=false;

	if(strstr(av[1],"Y")!=NULL)
        tempArg.b_Y=true;
	else
		tempArg.b_Y=false;

	if(strstr(av[1],"G")!=NULL)
		tempArg.b_G=true;
	else
		tempArg.b_G=false;

	if( ac<= (int)tempArg.b_t + (int)tempArg.b_v + (int) tempArg.b_d +3)
	{
		OnHelp();
		exit (FAILED);
	}

	int startTimeArgIndex;

	if(tempArg.b_t)
	{
		startTimeArgIndex=3;
		tempArg.lidarpro_height=atof(av[2]);
		if (tempArg.lidarpro_height>60.0)   //Well , I still do recommend km unit..
		{
			tempArg.lidarpro_height /=1000.0;
		}
	}
	else
	{
		startTimeArgIndex=2;
		tempArg.lidarpro_height=-1;
	}

	string startTimeStr=av[startTimeArgIndex];
	string endTimeStr=av[startTimeArgIndex+1];
	tempArg.startTimeSecInt=YYYYMMDDhhmmss2Int(startTimeStr);
	tempArg.endTimeSecInt=YYYYMMDDhhmmss2Int(endTimeStr);

	if(tempArg.b_v)
		tempArg.averMinInt= atoi(av[startTimeArgIndex+2]);
	else
		tempArg.averMinInt=0;

	if(tempArg.b_d)
	{	
		if(tempArg.b_v)
			tempArg.lidarpro_limit=atof(av[startTimeArgIndex+3]);
		else
			tempArg.lidarpro_limit=atof(av[startTimeArgIndex+2]);
		if(tempArg.lidarpro_limit>60.0)        //km is good, isn't it?
			tempArg.lidarpro_limit /= 1000.0; 
	}
	else
		tempArg.lidarpro_limit=-1;

	return tempArg;
}

LidarINI LoadINI(string iniFileName)
{
	LidarINI temp;
	ifstream iniFile ( iniFileName.c_str());
	if(!iniFile)
	{
		cout<<"Can't load ini file: "<<iniFileName<<endl<<endl;
		cout<<"Please make sure there's one such file that contains: sa  lidarConst  inputDataPath  outputDataPath etc..."<<endl;
		exit(FAILED);
	}
	iniFile>>temp.sa>>temp.lidarConst>>temp.atmosModel>>temp.alpha
		>>temp.inputPath>>temp.outputPath>>temp.outputSize
		>>temp.farrestAfterpulseAverage>>temp.AODcalculationHeightLimit
		>>temp.cloudDetectThreshold>>temp.cloudDetectThreshold2>>temp.cloudDetectThreshold3
		>>temp.mixlayerDetectThreshold>>temp.mixlayerDetectThreshold2>>temp.mixlayerDetectThreshold3
		>>temp.IMG_BACK_PARA_1>>temp.IMG_BACK_PARA_2
		>>temp.IMG_EXTC_PARA_1>>temp.IMG_EXTC_PARA_2;

	return temp;
}
